﻿using System.Collections.Generic;
using System;
using System.Text;

namespace Ex03.GarageLogic
{
    /// <summary>
    /// This class is an abstract class for an Electric 
    /// Powered Vehicle.
    /// Inherits from Vehicle
    /// </summary>
    public abstract class ElectricPoweredVehicle : Vehicle
    {
        private const string k_BatteryCapacityInHoursKey = "Battery Capacity In Hours";
        private const string k_HoursLeftInBatteryKey = "Hours Left In Battery";
        private const float k_MinimumHoursLeftInBattery = 0.0f;
        private const int Onehour = 60;
        private static readonly Dictionary<string, string> sr_ElectricPoweredVehicleForm;

        private float m_HoursLeftInBattery = 0.0f;

        /// <summary>
        /// This is a static constructor that will initialize the Electric 
        /// Powered Vehicles form 
        /// </summary>
        static ElectricPoweredVehicle()
        {
            sr_ElectricPoweredVehicleForm = new Dictionary<string, string>(VehicleForm);
            sr_ElectricPoweredVehicleForm.Add(k_HoursLeftInBatteryKey, null);
        }

        /// <summary>
        /// A constructor that will pass all input to its base
        /// </summary>
        /// <param name="i_PlateNumber">plate number needed by parent </param>
        /// <param name="i_NumberOfWheels">number of wheels needed by parent</param>
        /// <param name="i_WheelMaxAirPressure">wheel max air pressure needed by parent</param>
        protected ElectricPoweredVehicle(string i_PlateNumber, int i_NumberOfWheels, float i_WheelMaxAirPressure)
            : base(i_PlateNumber, i_NumberOfWheels, i_WheelMaxAirPressure)
        {         
        }

        /// <summary>
        /// This is the main initialization function of this object
        /// This function will receive a form with all the data needed for the initialization
        /// </summary>
        /// <param name="i_CreationForm">
        ///     A key value Dictionary where key is the name of the member 
        ///     to initialize and value is the new value
        /// </param>
        public override void Initialize(Dictionary<string, string> i_CreationForm)
        {
            base.Initialize(i_CreationForm);
            bool isGetValueSucceded;
            bool isParseSucceded;
            string hoursLeftInBatteryString;
            float hoursLeftInBatteryTemp;

            isGetValueSucceded = i_CreationForm.TryGetValue(k_HoursLeftInBatteryKey, out hoursLeftInBatteryString);
            isParseSucceded = float.TryParse(hoursLeftInBatteryString, out hoursLeftInBatteryTemp);
            if (!isGetValueSucceded || !isParseSucceded)
            {
                throw new FormatException("Hours left in battery is invalid");
            }

            if (hoursLeftInBatteryTemp < 0 || hoursLeftInBatteryTemp > BatteryCapacityInHours)
            {
                throw new ValueOutOfRangeException("Hours left in battery out of range", k_MinimumHoursLeftInBattery, BatteryCapacityInHours);
            }

            m_HoursLeftInBattery = hoursLeftInBatteryTemp;
        }

        /// <summary>
        /// An override property to get the energy left in percent
        /// </summary>
        public override float EnergyLeftInPercent
        {
            get { return (HoursLeftInBattery / BatteryCapacityInHours) * 100; }
        }

        /// <summary>
        /// An abstract property to get the battery capacity in hours
        /// </summary>
        public abstract float BatteryCapacityInHours { get; }
        
        /// <summary>
        /// A property to get the hours left in battery
        /// </summary>
        public float HoursLeftInBattery
        {
            get { return m_HoursLeftInBattery; }
        }

        /// <summary>
        /// A property to get the electric powered vehicle form
        /// <remarks>will return a new form</remarks>
        /// </summary>
        protected static Dictionary<string, string> ElectricPoweredVehicleForm
        {
            get { return new Dictionary<string, string>(sr_ElectricPoweredVehicleForm); }
        }

        /// <summary>
        /// Allows you to charge the vehicles battery
        /// </summary>
        /// <param name="i_AmountOfMinutes">The amount to charge 
        ///     <remarks>
        ///         Must be larger then 0 and the sum of current hours left in battery and this value should not excised 
        ///         the battery capacity, in such a case will throw ValueOutOfRangeException
        ///     </remarks>
        /// </param>
        public void ChargeBattery(float i_AmountOfMinutes)
        {
            float targetHoursLeftInBattery = m_HoursLeftInBattery + (i_AmountOfMinutes / Onehour);
            if ((targetHoursLeftInBattery > BatteryCapacityInHours) || (targetHoursLeftInBattery < k_MinimumHoursLeftInBattery))
            {
                throw new ValueOutOfRangeException("Hours left in battery out of range", k_MinimumHoursLeftInBattery, BatteryCapacityInHours);
            }

            m_HoursLeftInBattery = targetHoursLeftInBattery;
        }

        /// <summary>
        /// Return a string representation object members as pair 
        /// members name and variable value
        /// </summary>
        /// <returns>string "varName + Vehicle.k_ToStirngPairDelimiter + varValue + Vehicle.sr_ToStirngEndOfPairDelimiter"</returns>
        public override string ToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(base.ToString());
            stringBuilderResult.Append(batteryCapacityInHoursToString());
            stringBuilderResult.Append(hoursLeftInBatteryString());

            return stringBuilderResult.ToString();
        }

        private string batteryCapacityInHoursToString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_BatteryCapacityInHoursKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(BatteryCapacityInHours);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }

        private string hoursLeftInBatteryString()
        {
            StringBuilder stringBuilderResult = new StringBuilder();

            stringBuilderResult.Append(k_HoursLeftInBatteryKey);
            stringBuilderResult.Append(Vehicle.k_ToStirngPairDelimiter);
            stringBuilderResult.Append(m_HoursLeftInBattery);
            stringBuilderResult.Append(Vehicle.sr_ToStirngEndOfPairDelimiter);

            return stringBuilderResult.ToString();
        }
    }
}
